package org.kd.websocket;

import java.io.IOException;
import java.net.URI;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import org.kd.common.base.controller.BaseController;
import org.kd.model.Emp;
import org.kd.model.Message;
import org.kd.model.DTO.EmpBTO;
import org.kd.model.DTO.EmpDTO;
import org.kd.model.DTO.PackMsgBTO;
import org.kd.model.DTO.SendMessageBTO;
import org.kd.service.EmpService;
import org.kd.service.MessageService;
import org.kd.utils.WebConstant;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.CloseStatus;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketHandler;
import org.springframework.web.socket.WebSocketMessage;
import org.springframework.web.socket.WebSocketSession;

import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;

/****
 * 处理websocket消息的handle
 * 
 * @author tangyu
 *
 */
@Component
public class MessageHandler extends BaseController implements WebSocketHandler {
	private final Logger logger = LoggerFactory.getLogger(this.getClass());
	@Autowired
	MessageService messageService;
	@Autowired
	EmpService empService;
	/**
	 * 在线用户session的储存
	 */
	private static final Map<Integer, WebSocketSession> userSocketSessionMap = new HashMap<Integer, WebSocketSession>();
	/**
	 * json转换器
	 */
	ObjectMapper mapper = new ObjectMapper();

	/*
	 * (non-Javadoc)连接断开的逻辑在这里体现
	 * 
	 * @see
	 * org.springframework.web.socket.WebSocketHandler#afterConnectionClosed(org
	 * .springframework.web.socket.WebSocketSession,
	 * org.springframework.web.socket.CloseStatus)
	 */
	public void afterConnectionClosed(WebSocketSession webSocketSession, CloseStatus closeStatus) throws Exception {
		Integer id = this.parsing(webSocketSession);
		if (webSocketSession.isOpen()) {
			webSocketSession.close();
		}
		userSocketSessionMap.remove(id);
		logger.info("链接退出系统 connect closed,status:{}", closeStatus);

	}

	/*
	 * (non-Javadoc)连接成功的逻辑在这里体现
	 * 
	 * @see org.springframework.web.socket.WebSocketHandler#
	 * afterConnectionEstablished(org.springframework.web.socket.
	 * WebSocketSession)
	 */
	public void afterConnectionEstablished(WebSocketSession webSocketSession) throws IOException {
		Integer id = this.parsing(webSocketSession);
		userSocketSessionMap.put(id, webSocketSession);
		
		Message model = new Message();
		model.setToId(id);
		model.setDelFlag(WebConstant.NODELETECODE);
		model.setStatus(WebConstant.NOT_SEND);
		List<Message> queryParamList = messageService.queryParamList(model);
		if(queryParamList.size() > 0){
			String offline = this.essembltOffline(queryParamList);
			this.sendOffline(webSocketSession,offline);
		}
		logger.info("链接 established!session info:{}", webSocketSession);
	}



	/*
	 * (non-Javadoc)接收到消息的逻辑在这里体现
	 * 
	 * @see org.springframework.web.socket.WebSocketHandler#handleMessage(org.
	 * springframework.web.socket.WebSocketSession,
	 * org.springframework.web.socket.WebSocketMessage)
	 */
	public void handleMessage(WebSocketSession webSocketSession, WebSocketMessage<?> webSocketMessage)
			throws Exception {
		String str = webSocketMessage.getPayload().toString();
		PackMsgBTO<SendMessageBTO<EmpBTO>> packMsgBTO = new PackMsgBTO<SendMessageBTO<EmpBTO>>();
		packMsgBTO = mapper.readValue(str, new TypeReference<PackMsgBTO<SendMessageBTO<EmpBTO>>>(){});

		PackMsgBTO<Message> chatMessage = new PackMsgBTO<Message>();
		chatMessage.setEmit(WebConstant.CHAT_MESSAGE);
		String type = packMsgBTO.getData().getTo().getType();
		if ("friend".equals(type)) {
			Message assembleFriend = this.assembleFriend(packMsgBTO);
			chatMessage.setData(assembleFriend);
			this.sendFriend(packMsgBTO.getData().getTo().getId(),chatMessage);
			
		} else if ("group".equals(type)) {
			Message assembleGroup = this.assembleGroup(packMsgBTO);
			chatMessage.setData(assembleGroup);
			this.sendGroup(packMsgBTO.getData().getMine().getId(),chatMessage);
		}
	}


	/*
	 * (non-Javadoc)传输异常的逻辑在这里体现
	 * 
	 * @see
	 * org.springframework.web.socket.WebSocketHandler#handleTransportError(org.
	 * springframework.web.socket.WebSocketSession, java.lang.Throwable)
	 */
	public void handleTransportError(WebSocketSession webSocketSession, Throwable throwable) throws Exception {
		logger.error("链接 chtch throwable,message is:", throwable);

	}

	public boolean supportsPartialMessages() {
		return false;
	}

	/**
	 * @功能:解析出登录id
	 * @作者:jh @代号:甲骨兽进化
	 * @时间:2018年4月11日
	 * @param webSocketSession
	 * @return
	 */
	private Integer parsing(WebSocketSession webSocketSession) {
		
		EmpDTO u = (EmpDTO) webSocketSession.getAttributes().get("user");
		return u.getId();
	}

	/**
	 *  @功能:发送离线消息
	 *  @作者:jh @代号:甲骨兽进化
	 *  @时间:2018年4月14日
	 *  @param webSocketSession
	 *  @param offline  
	 * @throws IOException 
	 */
	private void sendOffline(WebSocketSession webSocketSession, String offline) throws IOException {
		// TODO Auto-generated method stub
		webSocketSession.sendMessage(new TextMessage(offline, true));
		Message msg = new Message();
		msg.setToId(this.parsing(webSocketSession));
		msg.setStatus(WebConstant.SENDED);
		Integer num = messageService.updateByToId(msg);
	}
	
	/**
	 *  @功能:组装离线消息
	 *  @作者:jh @代号:甲骨兽进化
	 *  @时间:2018年4月14日
	 *  @param queryParamList  
	 * @return 
	 */
	private String essembltOffline(List<Message> queryParamList) {
		// TODO Auto-generated method stub
		PackMsgBTO<List<Message>> offLineMsg = new PackMsgBTO<List<Message>>();
		offLineMsg.setEmit(WebConstant.OFF_LINE_MESSAGE);
		offLineMsg.setData(queryParamList);
		return responseAPI.getJsonString(offLineMsg);
	}
	
	/**
	 * @功能:发送mag,单聊
	 * @作者:jh @代号:甲骨兽进化
	 * @时间:2018年4月11日
	 * @param id
	 * @param chatMessage
	 * @throws IOException 
	 */
	private void sendFriend(Integer id, PackMsgBTO<Message> chatMessage) throws IOException {
		// TODO Auto-generated method stub
		WebSocketSession webSocketSession = userSocketSessionMap.get(id);
		Message message = chatMessage.getData();
		message.setDelFlag(WebConstant.NODELETECODE);
		String emit = chatMessage.getEmit();
		Boolean b = false;
		b = webSocketSession != null ? webSocketSession.isOpen():false;
			if (b) {
				webSocketSession.sendMessage(new TextMessage(responseAPI.getJsonString(chatMessage), true));
				message.setStatus(WebConstant.SENDED);
				messageService.insert(message);
			}else {
				message.setStatus(WebConstant.NOT_SEND);
				messageService.insert(message);
			}
	}
	
	/**
	 * @param id 
	 * @功能:群消息发送
	 * @作者:jh @代号:甲骨兽进化
	 * @时间:2018年4月12日
	 * @param responseAPI.getJsonString(chatMessage)
	 * @throws IOException 
	 */
	private void sendGroup(Integer id, PackMsgBTO<Message> chatMessage) throws IOException {
		// TODO Auto-generated method stub
		Message message = chatMessage.getData();
		message.setDelFlag(WebConstant.NODELETECODE);
		
		this.saveGroupMsg(message);
		
		Iterator<Entry<Integer, WebSocketSession>> iterator = userSocketSessionMap.entrySet().iterator();
		while (iterator.hasNext()) {
			Map.Entry<Integer, WebSocketSession> entry = (Map.Entry<Integer, WebSocketSession>) iterator.next();
			WebSocketSession webSocketSession = entry.getValue();
			Boolean b = null;
			b = webSocketSession != null ? webSocketSession.isOpen():false;
				if(b ){
					if(message.getFromid() == this.parsing(webSocketSession)){
						message.setCid(null);
						message.setToId(this.parsing(webSocketSession));
						message.setStatus(WebConstant.NOT_SEND);
						Message param = messageService.queryByParam(message);
						param.setStatus(WebConstant.SENDED);
						param.setDelFlag(WebConstant.DELETECODE);
						Integer update = messageService.update(param);
					}else{
						webSocketSession.sendMessage(new TextMessage(responseAPI.getJsonString(chatMessage), true));
						message.setCid(null);
						message.setToId(this.parsing(webSocketSession));
						message.setStatus(WebConstant.NOT_SEND);
						Message param = messageService.queryByParam(message);
						param.setStatus(WebConstant.SENDED);
						Integer update = messageService.update(param);
					}
				}
		}
	}

	/**
	 *  @功能:保存群消息
	 *  @作者:jh @代号:甲骨兽进化
	 *  @时间:2018年4月17日
	 *  @param message  
	 */
	private void saveGroupMsg(Message message) {
		// TODO Auto-generated method stub
		message.setStatus(WebConstant.NOT_SEND);
		Emp e = new Emp();
		e.setDeptId(message.getId());
		e.setLogictodelete(WebConstant.NODELETECODE);
		List<Emp> paramList = empService.queryParamList(e);
		Iterator<Emp> iterator = paramList.iterator();
		while (iterator.hasNext()) {
			Emp emp = (Emp) iterator.next();
			message.setCid(null);
			message.setToId(emp.getId());
			messageService.insert(message);
		}
	}

	/**
	 * @param packMsgBTO
	 * @功能:friend组装数据
	 * @作者:jh @代号:甲骨兽进化
	 * @时间:2018年4月12日
	 * @return
	 */
	private Message assembleFriend(PackMsgBTO<SendMessageBTO<EmpBTO>> packMsgBTO) {
		// TODO Auto-generated method stub
		Message onMessageBTO = new Message();
		onMessageBTO.setUsername(packMsgBTO.getData().getMine().getUsername());
		onMessageBTO.setAvatar(packMsgBTO.getData().getMine().getAvatar());
		onMessageBTO.setId(packMsgBTO.getData().getMine().getId());
		onMessageBTO.setType(packMsgBTO.getData().getTo().getType());
		onMessageBTO.setContent(packMsgBTO.getData().getMine().getContent());
		onMessageBTO.setMine(false);
		onMessageBTO.setFromid(packMsgBTO.getData().getMine().getId());
		onMessageBTO.setTimestamp(new Date().getTime());
		onMessageBTO.setToId(packMsgBTO.getData().getTo().getId());
		return onMessageBTO;
	}
	/**
	 *  @功能:群消息组装
	 *  @作者:jh @代号:甲骨兽进化
	 *  @时间:2018年4月13日
	 *  @param packMsgBTO
	 *  @return  
	 */
	private Message assembleGroup(PackMsgBTO<SendMessageBTO<EmpBTO>> packMsgBTO) {
		// TODO Auto-generated method stub
		Message onMessageBTO = new Message();
		onMessageBTO.setUsername(packMsgBTO.getData().getMine().getUsername());
		onMessageBTO.setAvatar(packMsgBTO.getData().getMine().getAvatar());
		onMessageBTO.setId(packMsgBTO.getData().getTo().getId());
		onMessageBTO.setType(packMsgBTO.getData().getTo().getType());
		onMessageBTO.setContent(packMsgBTO.getData().getMine().getContent());
		onMessageBTO.setMine(false);
		onMessageBTO.setFromid(packMsgBTO.getData().getMine().getId());
		onMessageBTO.setTimestamp(new Date().getTime());
		onMessageBTO.setToId(packMsgBTO.getData().getTo().getId());
		return onMessageBTO;
	}
}
